/* usbEhcdUtil.h - Utility Functions for EHCI */

/* Copyright 2004-2005 Wind River Systems, Inc. 

   This software includes software licensed to Wind River Systems, Inc.
   by Wipro, Ltd. Wind River licensees may use this software according  
   to the terms of their Wind River license agreement(s) applicable to 
   this software.
*/

/*
Modification history
--------------------
01h,28mar05,pdg  non-PCI changes
01g,22mar05,mta  64-bit support added (SPR #104950)
01f,02feb05,pdg  Fix for multiple device connection/disconnection
01e,03aug04,ami  Warning Messages Removed
01d,23Jul03,gpd Incorporated the changes identified during testing on MIPS
01c,03Jul03,gpd fixed the bug with asynchronous schedule updation.
                Added separate reclamation lists for asynchronous and periodic
                Added reclamation lists for asynch and periodic request
                                        cancellation.
01b,26jun03,psp changing the code to WRS standards.
01a,25apr03,ram written.
*/

/*
DESCRIPTION
This contains the prototypes of the utility functions
which are used by the EHCI Driver.
*/

/*
INTERNAL
 *******************************************************************************
 * Filename         : usbEhcdUtil.h
 *
 * Copyright        :
 *
 * THE COPYRIGHT IN THE CONTENTS OF THIS SOFTWARE VEST WITH WIPRO
 * LIMITED A COMPANY INCORPORATED UNDER THE LAWS OF INDIA AND HAVING
 * ITS REGISTERED OFFICE AT DODDAKANNELLI SARJAPUR ROAD  BANGALORE
 * 560 035. DISTRIBUTION OR COPYING OF THIS SOFTWARE BY
 * ANY INDIVIDUAL OR ENTITY OTHER THAN THE ADDRESSEE IS STRICTLY
 * PROHIBITED AND MAY INCUR LEGAL LIABILITY. IF YOU ARE NOT THE
 * ADDRESSEE PLEASE NOTIFY US IMMEDIATELY BY PHONE OR BY RETURN EMAIL.
 * THE ADDRESSEE IS ADVISED TO MAINTAIN THE PROPRIETARY INTERESTS OF
 * THIS COPYRIGHT AS PER APPLICABLE LAWS.
 *
 *
 ******************************************************************************/



#ifndef __INCusbEhcdUtilh
#define __INCusbEhcdUtilh

#ifdef	__cplusplus
extern "C" {
#endif


/* defines */

/*Macro to Initialize USB_USB_EHCD_PIPE */
#define USB_EHCD_PIPE_INITIALIZE(pEHCDPipe)                                    \
{                                                                              \
    OS_MEMSET(pEHCDPipe, 0, sizeof(USB_EHCD_PIPE));                            \
    pEHCDPipe->PipeDeletedFlag = FALSE;                                        \
}

/* Macro to Add QH to asynchronousschedule */
#define USB_EHCD_ADD_TO_HC_ASYNCH_SCHEDULE(pHCDData,                           \
                                       pQH)                                    \
{                                                                              \
    /* To hold the field returned by GET_FIELD macro. */	               \
    UINT32 getField;				                               \
    /* Temporary pointer to hold the queue head */   		               \
    PUCHAR pQhPtr = NULL;                                                  \
									       \
    UINT32	uBusIndex = pHCDData->uBusIndex;/* bus index */		       \
								               \
    CACHE_DMA_INVALIDATE(pHCDData->pAsynchTailPipe->pQH, sizeof(USB_EHCD_QH)); \
                                                                               \
    getField = USB_EHCD_GET_BITFIELD(uBusIndex,				       \
               QH,			                                       \
               pHCDData->pAsynchTailPipe->pQH->uQueueHeadHorizontalLinkPointer,\
               HORIZONTAL_LINK_POINTER );			               \
                                                                               \
    USB_EHCD_SET_BITFIELD(uBusIndex,		       		      	       \
		QH, pQH->uQueueHeadHorizontalLinkPointer,                      \
               getField, HORIZONTAL_LINK_POINTER );           		       \
                                                                               \
                                                                               \
    /* Disable the asynchronous schedule */                                \
                                                                           \
    USB_EHCD_CLR_BIT(pHCDData,                                             \
                 USBCMD,                                                   \
                 ASYNCH_SCHEDULE_ENABLE);                                  \
									   \
    while ((USB_EHCD_GET_FIELD(pHCDData,                                   \
                               USBCMD,                                     \
                               ASYNCH_SCHEDULE_ENABLE) != 0) ||            \
               (USB_EHCD_GET_FIELD(pHCDData,                               \
                                   USBSTS,                                 \
                                   ASYCHRONOUS_SCHEDULE_STATUS) !=0))      \
        OS_DELAY_MS(1);                                                    \
								           \
    pQhPtr = (PUCHAR) pQH;                                                \
    pQhPtr += USB_EHCD_QH_HEADER_SIZE;                                    \
    /* Update the tail's next pointer */                                       \
    USB_EHCD_SET_BITFIELD(uBusIndex,		  	                       \
               QH,                                                  \
               pHCDData->pAsynchTailPipe->pQH->uQueueHeadHorizontalLinkPointer,\
              ((unsigned)USB_EHCD_CONVERT_TO_BUS_MEM(			       \
                                     pHCDData->uBusIndex,pQhPtr) >> 5),           \
               HORIZONTAL_LINK_POINTER );                                      \
                                                                               \
									       \
    /* This USB_EHCD_PIPE pointer's next element is the tail's next element*/  \
    pQH->pHCDPipe->pNext = pHCDData->pAsynchTailPipe->pNext;                   \
                                                                               \
    CACHE_DMA_FLUSH(pQH, sizeof(USB_EHCD_QH));                                 \
                                                                               \
    CACHE_DMA_FLUSH(pHCDData->pAsynchTailPipe->pQH, sizeof(USB_EHCD_QH));      \
                                                                               \
                                                                               \
    /* Enable the asynchronous schedule */                                 \
                                                                           \
    USB_EHCD_SET_BIT(pHCDData,                                             \
                 USBCMD,                                                   \
                 ASYNCH_SCHEDULE_ENABLE);                                  \
                                                                           \
    while ((USB_EHCD_GET_FIELD(pHCDData,                                   \
                               USBCMD,                                     \
                               ASYNCH_SCHEDULE_ENABLE) == 0) ||            \
               (USB_EHCD_GET_FIELD(pHCDData,                               \
                                   USBSTS,                                 \
                                   ASYCHRONOUS_SCHEDULE_STATUS) ==0))      \
            OS_DELAY_MS(1);                                                \
									\
    /* The tail pointer's next points to this QH's USB_EHCD_PIPE pointer */    \
    pHCDData->pAsynchTailPipe->pNext = pQH->pHCDPipe;                          \
                                                                               \
    /* Make this as the tail element */                                        \
    pHCDData->pAsynchTailPipe = pQH->pHCDPipe;                                 \
}

/* Macro to Add QH to Interrupt Schedule */
#define USB_EHCD_ADD_TO_HC_INTERRUPT_SCHEDULE(pHCDData,                        \
                                              uListIndex,                      \
                                              pQH)                             \
{                                                                              \
    /* To hold the field returned by GET_FIELD macro. */		       \
    UINT32  getField;				                               \
									       \
    UINT32	uBusIndex = pHCDData->uBusIndex;/* bus index */		       \
                                                                       	       \
    /* Pointer to the tail of the list */                                      \
    pUSB_EHCD_QH pTailQH = NULL;                                               \
                                                                               \
    /* temporary pointer to hold the queue head  */                            \
    PUCHAR       pQhPtr = NULL;                                     \
                                                                               \
    /* Copy the tail of the list */                                            \
    pTailQH = (pUSB_EHCD_QH)pHCDData->TreeListData[uListIndex].pTailPointer;   \
                                                                               \
    /* Retrieve the HCD accessible pointer */                                  \
                                                                               \
    pTailQH =(pUSB_EHCD_QH) ((UINT32)pTailQH -USB_EHCD_QH_HEADER_SIZE);        \
                                                                               \
    CACHE_DMA_INVALIDATE(pTailQH, sizeof(USB_EHCD_QH));                        \
                                                                               \
    /* Copy the next data structure type from the tail element */              \
    getField = USB_EHCD_GET_BITFIELD(pHCDData->uBusIndex,		       \
                                     QH,                                       \
                                     pTailQH->uQueueHeadHorizontalLinkPointer, \
        HORIZONTAL_LINK_POINTER_TYPE);      				       \
                                                                               \
    USB_EHCD_SET_BITFIELD(pHCDData->uBusIndex,		                      \
        QH,pQH->uQueueHeadHorizontalLinkPointer,                      		\
        getField, HORIZONTAL_LINK_POINTER_TYPE );         			\
                                                                               \
    /*                                                                         \
     * Copy tail element's 't' type which indicates whether the next           \
     * data structure is a valid data structure                                \
     */                                                                        \
    /* pQH->dword0.t = pTailQH->dword0.t; */					\
    										\
    getField = USB_EHCD_GET_BITFIELD(uBusIndex,		                       \
                        QH,                                          		\
                        pTailQH->uQueueHeadHorizontalLinkPointer,             \
                        HORIZONTAL_LINK_POINTER_T);			\
										\
    USB_EHCD_SET_BITFIELD(uBusIndex,		                                \
                        QH,pQH->uQueueHeadHorizontalLinkPointer,            \
                        getField,                				\
                        HORIZONTAL_LINK_POINTER_T);                \
                                                                               \
    /* The QH's next pointer should point to the tail's next element */        \
    /* pQH->dword0.queue_head_horizontal_link_pointer =                         \
                        pTailQH->dword0.queue_head_horizontal_link_pointer;  */   \
    getField = USB_EHCD_GET_BITFIELD(uBusIndex,	                    	       \
                        QH,                            \
                        pTailQH->uQueueHeadHorizontalLinkPointer,             \
                        HORIZONTAL_LINK_POINTER);				\
										\
    USB_EHCD_SET_BITFIELD(uBusIndex,			                        \
                        QH,pQH->uQueueHeadHorizontalLinkPointer,                \
                        getField,                     			        \
                        HORIZONTAL_LINK_POINTER);                              \
										\
                                                                               \
    /* Update the next pointer of the QH */                                    \
    pQH->pNext = pTailQH->pNext;                                               \
                                                                               \
    CACHE_DMA_FLUSH(pQH, sizeof(USB_EHCD_QH));                                 \
                                                                               \
    /* Update the tail's next pointer */                                       \
    pTailQH->pNext = pQH;                                                      \
                                                                               \
    /* Update the tail pointer */                                              \
    pHCDData->TreeListData[uListIndex].pTailPointer = (pVOID)((UINT32)pQH +    \
				  USB_EHCD_QH_HEADER_SIZE);                     \
                                                                               \
                                                                               \
									       \
    /* Make the Queue Head point to the host controller accessable region     \
     * by adding the offest USB_EHCD_QH_HEADER_SIZE to queue head  */         \
                                                                              \
    pQhPtr = (PUCHAR)pQH;                                                     \
    pQhPtr += USB_EHCD_QH_HEADER_SIZE;                                        \
									      \
									      \
    /* Update the next element of the tail pointer */                          \
    /* pTailQH->dword0.queue_head_horizontal_link_pointer =                    \
                                         (unsigned) (pQH) >> 5;  */            \
    USB_EHCD_SET_BITFIELD(uBusIndex,			                      \
                        QH,pTailQH->uQueueHeadHorizontalLinkPointer,         \
                        (((unsigned)(USB_EHCD_CONVERT_TO_BUS_MEM(	       \
                                     pHCDData->uBusIndex,pQhPtr))) >> 5),     \
                        HORIZONTAL_LINK_POINTER);                              \
                                                                               \
    CACHE_DMA_FLUSH(pTailQH, sizeof(USB_EHCD_QH));                             \
}
/* Macro to add pointer to USB_EHCD_PIPE in Asynch Reclamation List */
#define  USB_EHCD_ADD_TO_ASYNCH_RECLAMATION_LIST(pHCDData,                     \
                                                pHCDPipe)                      \
{                                                                              \
    /* Exclusively access the list */                                          \
    OS_WAIT_FOR_EVENT(pHCDData->ReclamationListSynchEventID, OS_WAIT_INFINITE);\
                                                                               \
    /* Add to the list */                                                      \
    pHCDPipe->pNext = pHCDData->pAsynchReclamationListHead;                    \
                                                                               \
    /* Update the asynch reclamation list head */                              \
    pHCDData->pAsynchReclamationListHead = pHCDPipe;                           \
                                                                               \
    /* Release the exclusive access */                                         \
    OS_RELEASE_EVENT(pHCDData->ReclamationListSynchEventID);                   \
}

/* Macro to add pointer to USB_EHCD_PIPE in Periodic Reclamation List */
#define  USB_EHCD_ADD_TO_PERIODIC_RECLAMATION_LIST(pHCDData,                   \
                                                   pHCDPipe)                   \
{                                                                              \
    /* Exclusively access the list */                                          \
    OS_WAIT_FOR_EVENT(pHCDData->ReclamationListSynchEventID, OS_WAIT_INFINITE);\
                                                                               \
    /* Add to the list */                                                      \
    pHCDPipe->pNext = pHCDData->pPeriodicReclamationListHead;                  \
                                                                               \
    /* Update the periodic reclamation list head */                            \
    pHCDData->pPeriodicReclamationListHead = pHCDPipe;                         \
                                                                               \
    /* Release the exclusive access */                                         \
    OS_RELEASE_EVENT(pHCDData->ReclamationListSynchEventID);                   \
}

/* Macro to add pointer to USB_EHCD_PIPE in Isoch pipe List */
#define  USB_EHCD_ADD_TO_ISOCH_PIPE_LIST(pHCDData,                     \
                                                pHCDPipe)                      \
{                                                                              \
    /* Exclusively access the list */                                          \
    OS_WAIT_FOR_EVENT(pHCDData->ReclamationListSynchEventID, OS_WAIT_INFINITE);\
                                                                               \
    /* Add to the list */                                                      \
    pHCDPipe->pNext = pHCDData->pIsochPipeList;                    \
                                                                               \
    /* Update the asynch reclamation list head */                              \
    pHCDData->pIsochPipeList = pHCDPipe;                           \
                                                                               \
    /* Release the exclusive access */                                         \
    OS_RELEASE_EVENT(pHCDData->ReclamationListSynchEventID);                   \
}

/* Macro to add pointer to USB_EHCD_PIPE in Isoch pipe List */
#define  USB_EHCD_REMOVE_ISOCH_PIPE(pHCDData,                     \
                                                pHCDPipe)         \
{                                                                 \
    pUSB_EHCD_PIPE pTempPipe;                                     \
                                                                  \
    if (pHCDPipe == pHCDData->pIsochPipeList)                     \
        {                                                         \
        /* If it is the hesd element,                             \
         * update the head of list to next pointer */             \
         pHCDData->pIsochPipeList = pHCDPipe->pNext;              \
        }                                                         \
    else                                                          \
        {                                                         \
        /* Search for the pipe in the list */                     \
        for (pTempPipe = pHCDData->pIsochPipeList;                \
             (NULL != pTempPipe) &&                               \
             (pHCDPipe != pTempPipe->pNext);                      \
              pTempPipe = pTempPipe->pNext);                      \
                                                                  \
        /* If Pipe not found, Assert an error */                  \
        OS_ASSERT(NULL != pTempPipe);                             \
        pTempPipe->pNext = pHCDPipe->pNext;                       \
        }                                                         \
}


/* Macro to add request to the list of asynchronous requests to be removed */
#define  USB_EHCD_ADD_TO_ASYNCH_REQUEST_REMOVAL_LIST(pHCDData,                 \
                                                     pRequestInfo)             \
{                                                                              \
    /* Exclusively access the list */                                          \
    OS_WAIT_FOR_EVENT(pHCDData->ReclamationListSynchEventID, OS_WAIT_INFINITE);\
                                                                               \
    /* Add to the list */                                                      \
    pRequestInfo->pListRequest = pHCDData->pHeadAsynchCancelList;              \
                                                                               \
    /* Update the asynch cancel request list */                                \
    pHCDData->pHeadAsynchCancelList = pRequestInfo;                            \
                                                                               \
    /* Release the exclusive access */                                         \
    OS_RELEASE_EVENT(pHCDData->ReclamationListSynchEventID);                   \
}

/* Macro to add request to the list of periodic requests to be removed */
#define  USB_EHCD_ADD_TO_PERIODIC_REQUEST_REMOVAL_LIST(pHCDData,               \
                                                       pRequestInfo)           \
{                                                                              \
    /* Exclusively access the list */                                          \
    OS_WAIT_FOR_EVENT(pHCDData->ReclamationListSynchEventID, OS_WAIT_INFINITE);\
                                                                               \
    /* Add to the periodic list */                                             \
    pRequestInfo->pListRequest = pHCDData->pHeadPeriodicCancelList;            \
                                                                               \
    /* Update the periodic cancel request list */                              \
    pHCDData->pHeadPeriodicCancelList = pRequestInfo;                          \
                                                                               \
    /* Release the exclusive access */                                         \
    OS_RELEASE_EVENT(pHCDData->ReclamationListSynchEventID);                   \
}

/*Macro to add the request to Request list maintained Host Controller Driver */
#define  USB_EHCD_ADD_TO_HCD_REQUEST_LIST(pHCDData,                            \
                                      pRequest)                                \
{                                                                              \
    /*                                                                         \
     * If there is no element in the list,                                     \
     * make the head and tail point to the request                             \
     */                                                                        \
    if (NULL == pHCDData->pRequestQueueHead)                                   \
    {                                                                          \
        pHCDData->pRequestQueueHead = pRequest;                                \
        pHCDData->pRequestQueueTail = pRequest;                                \
    }                                                                          \
    else                                                                       \
    {                                                                          \
        /* Update the next pointer of the tail element */                      \
    	pHCDData->pRequestQueueTail->pListRequest = pRequest;                  \
    	/* Update the tail element to point to the request */                  \
        pHCDData->pRequestQueueTail = pRequest;                                \
    }                                                                          \
                                                                               \
}

/*Macro to add the request to requests list maintained for the endpoint. */
#define  USB_EHCD_ADD_TO_ENDPOINT_LIST(pHCDData,                               \
                                   pRequest)                                   \
{                                                                              \
                                                                               \
    /*                                                                         \
     * If there is no element in the list,                                     \
     * make the head and tail point to the request                             \
     */                                                                        \
    if (NULL == pRequest->pHCDPipe->pRequestQueueHead)                         \
    {                                                                          \
        pRequest->pHCDPipe->pRequestQueueHead = pRequest;                      \
        pRequest->pHCDPipe->pRequestQueueTail = pRequest;                      \
    }                                                                          \
    else                                                                       \
    {                                                                          \
        /* Update the next pointer of the tail element */                      \
    	pRequest->pHCDPipe->pRequestQueueTail->pNext = pRequest;               \
    	/* Update the tail element to point to the request */                  \
        pRequest->pHCDPipe->pRequestQueueTail = pRequest;                      \
    }                                                                          \
}

/* This macro is used to to delete the request from request list maintained
 * for the endpoint */
#define  USB_EHCD_DELETE_FROM_ENDPOINT_LIST(pRequestInfo)          \
{                                                                  \
                                                                   \
     /* Remove the request from the Endpoint list - Start */       \
                                                                   \
    /* Extract the pipe pointer for the request */                 \
                                                                   \
    pUSB_EHCD_PIPE pHCDPipe = pRequestInfo->pHCDPipe;              \
                                                                   \
    /* Check if it is the head element */                          \
                                                                   \
    if (pRequestInfo == pHCDPipe->pRequestQueueHead)               \
        {                                                          \
        /* If it is the only element,                              \
         * update the head and tail pointers to NULL */            \
                                                                   \
        if (pRequestInfo == pHCDPipe->pRequestQueueTail)           \
            {                                                      \
            pHCDPipe->pRequestQueueTail = NULL;                    \
            pHCDPipe->pRequestQueueHead = NULL;                    \
                                                                   \
            }                                                      \
                                                                   \
        /* Update the head element */                              \
        else                                                       \
            {                                                      \
            pHCDPipe->pRequestQueueHead = pRequestInfo->pNext;     \
            }                                                      \
        }                                                          \
                                                                   \
    /* if it is not head element */                                \
    else                                                           \
        {                                                          \
        pUSB_EHCD_REQUEST_INFO pTempRequestInfo;                   \
                                                                   \
        /* Search for the request in the list */                   \
                                                                   \
        for (pTempRequestInfo = pHCDPipe->pRequestQueueHead;       \
            (NULL != pTempRequestInfo) &&                          \
            (pTempRequestInfo->pNext != pRequestInfo);             \
            pTempRequestInfo = pTempRequestInfo->pNext);           \
                               	                                   \
		if (pTempRequestInfo != NULL)							   \
  		   {													   \
        	/* Update the next pointers */                         \
        	pTempRequestInfo->pNext = pRequestInfo->pNext;         \
		   }													   \
        }                                                          \
    /* Remove the request from the Endpoint list - End */          \
                                                                   \
}

/* This macro is used to to delete the request from request list maintained
 * for the endpoint */
#define  USB_EHCD_DELETE_FROM_HCD_LIST(pRequestInfo, pEHCDData)       \
{                                                                     \
								                                      \
    /* If this is the head element */				                  \
								                                      \
    if (pRequestInfo == pEHCDData->pRequestQueueHead)                 \
        {                                                             \
        /* Update the head of the request list */                     \
        pEHCDData->pRequestQueueHead = pRequestInfo->pListRequest;    \
								                                      \
        /* Update the tail to NULL if the head is NULL */             \
        if (NULL == pEHCDData->pRequestQueueHead)                     \
            {                                                         \
            pEHCDData->pRequestQueueTail = NULL;                      \
            }                                                         \
        }                                                             \
    else                                                              \
        {                                                             \
       	/* if it is not head element */                               \
        pUSB_EHCD_REQUEST_INFO pTempRequestInfo;                      \
                                                                      \
        /* Search for the request in the list */                      \
                                                                      \
        for (pTempRequestInfo = pEHCDData->pRequestQueueHead;         \
            (NULL != pTempRequestInfo) &&                             \
            (pTempRequestInfo->pListRequest != pRequestInfo);         \
            pTempRequestInfo = pTempRequestInfo->pListRequest);       \
                                                                      \
        /* If the temporary request pointer is NULL,                  \
        * it is an error                                              \
        */                                                            \
        OS_ASSERT(NULL != pTempRequestInfo);                          \
                                                                      \
        /* Update the next pointers */                                \
        pTempRequestInfo->pListRequest = pRequestInfo->pListRequest;  \
                                                                      \
        /* If List Request for TempRequest is NULL, the update        \
        Tail to Temp request */                                       \
                                                                      \
        if (NULL == pTempRequestInfo->pListRequest)                   \
           {                                                          \
           pEHCDData->pRequestQueueTail = pTempRequestInfo;           \
           }                                                          \
        }							      \
}

/* This macro is used to to delete the request from request list maintained
 * for the endpoint */
#define  USB_EHCD_UNLINK_ISOCH_REQ(pEHCDData, pRequestInfo, uSpeed)               \
{							                                           \
   /* If it is a full speed isochronous endpoint,		               \
    * update the SITD's link pointers */			                   \
								                                       \
    if (USBHST_FULL_SPEED == uSpeed)				                   \
        {							                                   \
								                                       \
        /* Pointer to the SITD data structure */		               \
								                                       \
        pUSB_EHCD_SITD pSITD = NULL;				                   \
								                                       \
        /* Unlinking all SITDs from hardware frame list. */	           \
								                                       \
            /* Extract the head of the request */		               \
            pSITD = (pUSB_EHCD_SITD)pRequestInfo->pHead;	           \
								                                       \
            /* Remove all the SITDs from request list. */	           \
            while (NULL != pSITD)				                       \
                {						                               \
                usbEhcdUnLinkSITD(pEHCDData, pSITD);		           \
                pSITD = pSITD->pVerticalNext;			               \
                }						                               \
								                                       \
        } /* End of Full speed isochronous endpoint removal handling */\
                                                                       \
    /* It is a high speed endpoint, update the ITD's link pointers */  \
    else                                                               \
       {                                                               \
       /* Pointer to the ITD data structure */                         \
                                                                       \
        pUSB_EHCD_ITD pITD = NULL;                                     \
                                                                       \
        /* Unlinking all ITDs from hardware frame list. */             \
                                                                       \
            /* Extract the head of the request */                      \
            pITD = (pUSB_EHCD_ITD)pRequestInfo->pHead;                 \
                                                                       \
            /* Remove all the SITDs from request list. */              \
            while (NULL != pITD)                                       \
                {                                                      \
                usbEhcdUnLinkITD(pEHCDData, pITD);                     \
                pITD = pITD->pVerticalNext;                            \
                }                                                      \
                                                                       \
       }/* End of high speed isochronous endpoint removal handling */  \
}


/* This macro is used to calculate the bandwidth occupied in the frame */
#define USB_EHCD_CALCULATE_FRAME_BANDWIDTH(pEHCDData, uFrameIndex, uCalBandwidth)  \
{                                                                              \
    /* To hold the index into the microframe array */                          \
    UINT32 uMicroFrameCount = 0;                                               \
                                                                               \
    /* This loop adds up the bandwidth in every microframe */                  \
    for (uMicroFrameCount = 0;                                                 \
         uMicroFrameCount < USB_EHCD_MAX_MICROFRAME_NUMBER;                    \
         uMicroFrameCount++)                                                   \
    {                                                                          \
        uCalBandwidth +=													   \
			 pEHCDData->FrameBandwidth[uFrameIndex][uMicroFrameCount];     	   \
    }                                                                          \
}

/*This macro is used to calculate the bandwidth occupied in the microframes
 specified by the mask. */
#define USB_EHCD_CALCULATE_BW_MICROFRAMES(pHCDData,                            \
                                      uFrameMask,                              \
                                      uFrameIndex,                             \
                                      uCalBandwidth)                           \
{                                                                              \
    /* To hold the index into the microframes in a frame */                    \
    UINT8 uIndex = 0;                                                          \
                                                                               \
    /*                                                                         \
     * If this microframe is to be acounted                                    \
     * for bandwidth calculation, calculate                                    \
     */                                                                        \
    for (uIndex = 0; USB_EHCD_MAX_MICROFRAME_NUMBER > uIndex; uIndex++)        \
    {                                                                          \
        /* Check if this microframe's bandwidth is to be calculated */         \
    	if (0 != ((uFrameMask >> uIndex) & 0x01))                              \
    	{                                                                      \
            uCalBandwidth += pHCDData->FrameBandwidth[uFrameIndex][uIndex];    \
    	}                                                                      \
    }                                                                          \
}
/*  This macro is used to calculate the traversal count */
 #define USB_EHCD_CALCULATE_TRAVERSAL_COUNT(uPollInterval, uTraversalCount)    \
{                                                                              \
	/*                                                                         \
     * If the pollinterval is between 32(not including 32) and 16              \
	 * the list needs to be traversed once                                     \
	 */                                                                        \
	if (16 <= uPollInterval)                                                   \
    {                                                                          \
        uTraversalCount = 1;                                                   \
    }                                                                          \
    /* Pollinterval lies between 8 and 16(excluded) */                         \
    else if (8 <= uPollInterval)                                               \
    {                                                                          \
    	uTraversalCount = 2;                                                   \
    }                                                                          \
    /* Pollinterval lies between 4 and 8(excluded) */                          \
    else if (4 <= uPollInterval)                                               \
    {                                                                          \
    	uTraversalCount = 3;                                                   \
    }                                                                          \
    /* Pollinterval lies between 2 and 4(excluded) */                          \
    else if (2 <= uPollInterval)                                               \
    {                                                                          \
    	uTraversalCount = 4;                                                   \
    }                                                                          \
    /* Polling interval is 1 */                                                \
    else                                                                       \
    {                                                                          \
    	uTraversalCount = 5;                                                   \
    }                                                                          \
}

/*  This macro is used to calculate the traversal count */
 #define USB_EHCD_CALCULATE_LEAF_START_INDEX(uPollInterval, uTreeListCount)    \
{                                                                              \
	/*                                                                         \
     * If the pollinterval is between 32(not including 32) and 16              \
	 * the list needs to be traversed once                                     \
	 */                                                                        \
	if (16 <= uPollInterval)                                                   \
    {                                                                          \
        uTraversalCount = 1;                                                   \
    }                                                                          \
    /* Pollinterval lies between 8 and 16(excluded) */                         \
    else if (8 <= uPollInterval)                                               \
    {                                                                          \
    	uTraversalCount = 2;                                                   \
    }                                                                          \
    /* Pollinterval lies between 4 and 8(excluded) */                          \
    else if (4 <= uPollInterval)                                               \
    {                                                                          \
    	uTraversalCount = 3;                                                   \
    }                                                                          \
    /* Pollinterval lies between 2 and 4(excluded) */                          \
    else if (2 <= uPollInterval)                                               \
    {                                                                          \
    	uTraversalCount = 4;                                                   \
    }                                                                          \
    /* Polling interval is 1 */                                                \
    else                                                                       \
    {                                                                          \
    	uTraversalCount = 5;                                                   \
    }                                                                          \
}

#define USB_EHCD_GET_POLL_INTERVAL(uPollInterval)                              \
{                                                                              \
    /* Calculate the polling interval in terms of frames */                    \
                                                                               \
    if (0 != (uPollInterval % USB_EHCD_MAX_MICROFRAME_NUMBER))                 \
        {                                                                      \
        uPollInterval = 1;                                                     \
        }                                                                      \
    else                                                                       \
        {                                                                      \
        uPollInterval /= USB_EHCD_MAX_MICROFRAME_NUMBER;                       \
        }                                                                      \
                                                                               \
    /* If the bandwidth is more than what is supported,                        \
     * update the polling interval to the supported polling interval           \
     */                                                                        \
                                                                               \
    if (USB_EHCD_MAX_USB11_INTERRUPT_POLL_INTERVAL <                           \
        uPollInterval)                                                         \
        {                                                                      \
        uPollInterval = USB_EHCD_MAX_USB11_INTERRUPT_POLL_INTERVAL;            \
        }                                                                      \
}                                                                              

#define USB_EHCD_GET_ISOCH_BANDWIDTH(pHCDData, IsochBW)                        \
{                                                                              \
    UINT32 uFrameIndex, uUFrameIndex;                                          \
    for (uFrameIndex = 0;                                                      \
         USB_EHCD_MAX_FRAMELIST_SIZE > uFrameIndex;                            \
         uFrameIndex++)                                                        \
    {                                                                          \
        for (uUFrameIndex = 0;                                                 \
             USB_EHCD_MAX_MICROFRAME_NUMBER > uUFrameIndex;                    \
             uUFrameIndex++)                                                   \
             {                                                                 \
             IsochBW[uFrameIndex][uUFrameIndex]                                \
             = pHCDData->FrameListData[uFrameIndex].                           \
                         uBandwidth[uUFrameIndex];                             \
             }                                                                 \
    }                                                                          \
}                                                                              
                                                                               
#define USB_EHCD_GET_INTERRUPT_BANDWIDTH(pHCDData, InterruptBW)                \
{                                                                              \
    UINT32 uFrameIndex, uUFrameIndex;                                          \
    for (uFrameIndex = 0;                                                      \
         USB_EHCD_MAX_TREE_NODES > uFrameIndex;                                \
         uFrameIndex++)                                                        \
    {                                                                          \
 	for (uUFrameIndex = 0;                                                 \
             USB_EHCD_MAX_MICROFRAME_NUMBER > uUFrameIndex;                    \
             uUFrameIndex++)                                                   \
             {                                                                 \
             InterruptBW[uFrameIndex][uUFrameIndex]                            \
             = pHCDData->TreeListData[uFrameIndex].                                 \
                         uBandwidth[uUFrameIndex];                             \
             }                                                                 \
    }                                                                          \
}                                                                              
                                                                               
                                                                               
#define USB_EHCD_GET_FRAME_BANDWIDTH(pHCDData, IsochBW, InterruptBW, pTotalFrameBW)                        \
{                                                                              \
    UINT32 uFrameIndex, uUFrameIndex, uBandwidth, uTreeListIndex;              \
    /* This loop calculates bandwidth for each frame */                        \
                                                                               \
    for (uFrameIndex =0;                                                       \
         USB_EHCD_MAX_FRAMELIST_SIZE > uFrameIndex;                            \
         uFrameIndex++)                                                        \
        {                                                                      \
        /* This loop will calculates bandwidth for                             \
           each microframes in a frame */                                      \
                                                                               \
        for (uUFrameIndex = 0;                                                 \
             USB_EHCD_MAX_MICROFRAME_NUMBER > uUFrameIndex;                    \
             uUFrameIndex++)                                                   \
            {                                                                  \
                                                                               \
            /* Copy the bandwidth occupied                                     \
             * in the frame by isochronous endpoints                           \
             */                                                                \
            uBandwidth = IsochBW[uFrameIndex][uUFrameIndex];                   \
                                                                               \
            /* Hold the index of the list into the periodic tree */            \
                                                                               \
            uTreeListIndex                                                     \
            = pHCDData->FrameListData[uFrameIndex].uNextListIndex;             \
                                                                               \
            /* This loop calculates the bandwidth for                          \
               tree list data in the microframe                                \
            */                                                                 \
                                                                               \
            for (; ((int)uTreeListIndex != USB_EHCD_NO_LIST);                  \
                   uTreeListIndex                                              \
                   = pHCDData->TreeListData[uTreeListIndex].                   \
                                            uNextListIndex)                    \
                                                                               \
                {                                                              \
                uBandwidth +=                                                  \
                    InterruptBW[uTreeListIndex][uUFrameIndex];                 \
                }                                                              \
                                                                               \
            pTotalFrameBW[uFrameIndex] += uBandwidth;                          \
            } /* End of loop for each microframe */                            \
        } /* End of loop for each frame */                                     \
                                                                               \
}                                                                              
                                                                               
                                                                               
                                                                              
/* function declarations */

extern VOID usbEhcdFreeAllLists(VOID);

extern VOID * usbEhcdAlign
	(
	VOID * pMemory,
    UINT32  uAlignment
	);

extern pUSB_EHCD_QH usbEhcdFormEmptyQH
    (
    pUSB_EHCD_DATA  pHCDData
    );

extern INT32 usbEhcdCalculateBusTime
	(
	UINT32 uSpeed,
    UINT32 uDirection,
    UINT32 uPipeType,
    UINT32 uDataByteCount
	);

extern BOOLEAN usbEhcdCheckBandwidth
	(
	pUSB_EHCD_DATA  pHCDData,
    ULONG       uBandwidth,
    UINT32        uSpeed,
    pUSBHST_ENDPOINT_DESCRIPTOR		pEndpointDesc,
    UINT32 *	puListIndex,
    UINT32 *    puMicroFrameMask
	);

extern BOOLEAN usbEhcdAddToFreeQHList
	(
	pUSB_EHCD_QH pQH
	);

extern BOOLEAN usbEhcdAddToFreeQTDList
	(
	pUSB_EHCD_QTD pQTD
	);

extern BOOLEAN usbEhcdAddToFreeITDList
	(
	pUSB_EHCD_ITD pITD
	);

extern BOOLEAN usbEhcdAddToFreeSITDList
	(
	pUSB_EHCD_SITD pSITD
	);

extern pUSB_EHCD_QTD usbEhcdGetFreeQTD
    (
    UINT32	uSize
    );

extern pUSB_EHCD_QH usbEhcdGetFreeQH
    (
    UINT32	uSize
    );

extern pUSB_EHCD_ITD usbEhcdGetFreeITD
    (
    UINT32	uSize
    );

extern pUSB_EHCD_SITD usbEhcdGetFreeSITD
    (
    UINT32	uSize
    );

extern pUSB_EHCD_QTD usbEhcdFormEmptyQTD
    (
    pUSB_EHCD_DATA  pHCDData
    );

extern VOID usbEhcdUpdateNonIsochStatusAndBytes
    (
    UINT8	index,
    pUSB_EHCD_QTD pHead,
    pUSB_EHCD_QTD pTail,
    pUSBHST_URB pUrb
    );

extern VOID usbEhcdUpdateITDData
    (
    UINT8	index,
    pUSB_EHCD_ITD pHead,   /* Pointer to the head QTD */
    pUSB_EHCD_ITD pTail,   /* Pointer to the tail QTD */
    pUSBHST_ISO_PACKET_DESC pPacketDes, /* Pointer to the Packet descriptor */
    UINT8 uMicroFrameMask
    );

extern VOID usbEhcdUpdateSITDData
    (
    UINT8	index,
    pUSB_EHCD_SITD pHead,   /* Pointer to the head QTD */
    pUSB_EHCD_SITD pTail,   /* Pointer to the tail QTD */
    pUSBHST_ISO_PACKET_DESC pPacketDes /* Pointer to the Packet descriptor */
    );

extern VOID usbEhcdUnLinkSITD
    (
    pUSB_EHCD_DATA  pHCDData, /* Pointer to the EHCD_DATA structure */
    pUSB_EHCD_SITD   pSITD     /* Pointer to the tail SITD */
    );

extern VOID usbEhcdUnLinkITD
    (
    pUSB_EHCD_DATA  pHCDData, /* Pointer to the EHCD_DATA structure */
    pUSB_EHCD_ITD   pITD     /* Pointer to the tail SITD */
    );

extern BOOLEAN usbEhcdCopyRHInterruptData
	(
	pUSB_EHCD_DATA  pHCDData,
    UINT32      uStatusChange
	);

extern BOOLEAN usbEhcdUpdateBandwidth
	(
	pUSB_EHCD_DATA pHCDData
	);

extern UINT32 usbEhcdFillQTDBuffer
    (
    UINT8	index,
    pUSB_EHCD_QTD    pQTD,
    VOID   *    pBuffer,
    UINT32       uSize,
    UINT32          uMaxPacketSize
    );
extern BOOLEAN usbEhcdCreateQTDs
    (
    pUSB_EHCD_DATA  pHCDData,
    pUSB_EHCD_QTD *ppDataHead,
    pUSB_EHCD_QTD *ppDataTail,
    UCHAR *    pTransferBuffer,
    UINT32     uTransferLength,
    UINT32     uMaximumPacketSize,
    UINT8      uToggle,
    UINT8      uPID
    );
extern VOID usbEhcdLinkITDs
    (
    pUSB_EHCD_PIPE  pHCDPipe,
    pUSB_EHCD_DATA  pHCDData,
    UINT32          uFrameNumber,
    pUSB_EHCD_ITD   pHead,
    pUSB_EHCD_ITD   pTail
    );

extern VOID usbEhcdLinkSITDs
    (
    pUSB_EHCD_PIPE  pHCDPipe,
    pUSB_EHCD_DATA  pHCDData,
    UINT32          uFrameNumber,
    pUSB_EHCD_SITD   pHead,
    pUSB_EHCD_SITD   pTail
    );

extern BOOLEAN usbEhcdGenerateITDs
    (
    pUSB_EHCD_DATA  pHCDData,
    pUSB_EHCD_PIPE  pHCDPipe,
    pUSB_EHCD_ITD   *ppHead, 
    pUSB_EHCD_ITD   *ppTail, 
    UCHAR           *pBuffer,    
    UINT32          uPktCnt,    
    pUSBHST_ISO_PACKET_DESC pIsocPktDesc
    );

extern BOOLEAN usbEhcdGenerateSITDs
    (
    pUSB_EHCD_DATA  pHCDData,
    pUSB_EHCD_PIPE  pHCDPipe,
    pUSB_EHCD_SITD  *ppDataHead,
    pUSB_EHCD_SITD  *ppDataTail,
    UCHAR           *pTransferBuffer,
    UINT32          uPktCnt,         
    pUSBHST_ISO_PACKET_DESC pIsocPktDesc
    );

extern USBHST_STATUS usbEhcdSubBandwidth
    (
    pUSB_EHCD_DATA  pHCDData,
    UINT32      uDeviceAddress,
    UINT32      uDeviceSpeed,   
    pUSBHST_INTERFACE_DESCRIPTOR pInterfaceDesc,
    UINT32  *   pTotalFrameBW
    );

extern USBHST_STATUS usbEhcdSubDeviceBandwidth
    (
    pUSB_EHCD_DATA  pHCDData,
    UINT32      uDeviceAddress,
    UINT32  *   pTotalFrameBW
    );

extern BOOLEAN usbEhcdAddBandwidth
    (
    UINT32      uDeviceSpeed,
    pUSBHST_INTERFACE_DESCRIPTOR pInterfaceDesc,
    UINT32  *   pTotalFrameBW
    );


#ifdef	__cplusplus
}
#endif

#endif /* End of __INCusbEhcdUtilh */
/************************* End of file usbEhcdUtil.h***************************/



